﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Threading;
using System.IO;
using Pixysoft.Collections;

namespace Pixysoft.Cache
{
    /// <summary>
    /// http://www.cnblogs.com/lovko/archive/2009/01/05/1368810.html
    /// 
    /// TUTORIAL:
    /// 
    /// 1. 新建一个cache,例如EmailCache, 继承本类
    /// 2. 在cache里面新建一个Instance的静态方法，调用return GetInstance<EmailCache>();
    /// 3. 完成单例模式
    /// 
    /// </summary>
    [Serializable]
    public class GlobalObjectCache<T>
    {
        private static object syncRoot = new Object();

        protected List<ObjectTokenPair<T>> list = new List<ObjectTokenPair<T>>();



        public T Remove(string token)
        {
            bool removed = RemoveExpiredPair();

            T value = _Remove(token);

            //保存单例

            if (removed || value != null)
                SetInstance();

            return value;
        }

        public void Add(string token, T obj)
        {
            if (token == null)
                return;

            _Remove(token);

            list.Add(new ObjectTokenPair<T>(token, obj));

            SetInstance();//保存
        }

        public void Add(string token, T obj, DateTime endTime)
        {
            if (token == null)
                return;

            _Remove(token);

            list.Add(new ObjectTokenPair<T>(token, obj, endTime));

            SetInstance();//保存
        }

        public bool Contains(string token)
        {
            return Get(token) != null;
        }

        public void Clear()
        {
            list.Clear();

            SetInstance();//保存
        }

        public T Get(string token)
        {
            if (RemoveExpiredPair())
                SetInstance();

            foreach (ObjectTokenPair<T> pair in list)
            {
                if (pair.Token == token)
                    return pair.Obj;
            }

            return default(T);
        }

        public List<string> GetTokens()
        {
            if (RemoveExpiredPair())
                SetInstance();

            List<string> tokens = new List<string>();

            foreach (ObjectTokenPair<T> pair in list)
            {
                tokens.Add(pair.Token);
            }

            return tokens;

        }

        public bool IsEmpty
        {
            get { return list.Count == 0; }
        }




        /// <summary>
        /// 被序列化的时候调用
        /// </summary>
        public List<ObjectTokenPair<T>> List
        {
            get { return list; }
            set { list = value; }
        }







        private ObjectTokenPair<T> _Get(string token)
        {
            foreach (ObjectTokenPair<T> pair in list)
            {
                if (pair.Token == token)
                    return pair;
            }

            return null;
        }

        private T _Remove(string token)
        {
            ObjectTokenPair<T> value = _Get(token);

            list.Remove(value);

            if (value == null)
                return default(T);
            return value.Obj;
        }

        private bool RemoveExpiredPair()
        {
            bool changed = false;

            List<ObjectTokenPair<T>> removelist = new List<ObjectTokenPair<T>>();

            foreach (ObjectTokenPair<T> pair in list)
            {
                if (pair.IsExpired)
                    removelist.Add(pair);
            }

            foreach (ObjectTokenPair<T> pair in removelist)
            {
                list.Remove(pair);

                changed = true;
            }

            return changed;
        }

        private static string GetPath(Type type)
        {
            string id = Pixysoft.Security.MD5.GetMD5(type.Name);

            string path = AppDomain.CurrentDomain.BaseDirectory +
                @"\" +
                id +
                ".singleton";

            return path;
        }



        protected void SetInstance()
        {
            lock (syncRoot)
            {

                string path = GetPath(this.GetType());

                Pixysoft.IO.XmlExporter.Instance.XmlExport(path, this);
            }
        }

        protected static U GetInstance<U>()
        {
            lock (syncRoot)
            {
                string path = GetPath(typeof(U));

                U instance = default(U);

                if (!File.Exists(path))
                {
                    instance = Activator.CreateInstance<U>();

                    Pixysoft.IO.XmlExporter.Instance.XmlExport(path, instance);
                }
                else
                {
                    instance = Pixysoft.IO.XmlImporter.Instance.XmlImport<U>(path);
                }

                return instance;
            }
        }
    }
}